﻿/*************************************************************************************
 * 文 件 名:   HK_CreateGoByPath
 * 
 * 描    述:   本工具，可帮助用户在指定的路径上生成多个GameObject实例，并配置其位置偏移和旋转偏移。用户可以通过该工具快速在场景中布置物体，提高工作效率。
 * 
 * 版    本：  V1.1
 * 创 建 者：  京产肠饭
 * 创建时间：  2023/4/5
 * 链   接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

namespace HKTools
{
    [InitializeOnLoad]
    public class HK_CreateGoByPath : EditorWindow
    {
        const int CreateGoByPathPriority = 27;

        public GameObject template_Go;

        int prefabCount;
        float offsetHeight;
        float offsetYEuler;

        [MenuItem("HKTools/CreateGoByPath(基于路径创建工具)", priority = CreateGoByPathPriority)]
        static void OpenWindow()
        {
            HK_CreateGoByPath createGoByPath = GetWindow<HK_CreateGoByPath>("CreateGoByPath");

            createGoByPath.Show();
        }

        void OnGUI()
        {
            EditorGUILayout.Space();

            if (GUILayout.Button("生成 Path", GUILayout.Width(140)))
            {
                CreateLinePath();
            }

            EditorGUILayout.Space();

            if (GUILayout.Button("重置 Path 物体坐标轴", GUILayout.Width(140)))
            {
                ResetPathGoAxis();
            }

            EditorGUILayout.Space();

            if (GUILayout.Button("重置 Way Points 坐标", GUILayout.Width(140)))
            {
                ResetWayPointsPos();
            }

            EditorGUILayout.Space();

            template_Go = EditorGUILayout.ObjectField("需生成的物体：", template_Go, typeof(GameObject), true) as GameObject;

            EditorGUILayout.Space();

            prefabCount = EditorGUILayout.IntField("生成数量：", prefabCount);

            EditorGUILayout.Space();

            offsetHeight = EditorGUILayout.FloatField("高度偏移：", offsetHeight);

            EditorGUILayout.Space();

            offsetYEuler = EditorGUILayout.FloatField("Y轴旋转偏移：", offsetYEuler);

            EditorGUILayout.Space();

            if (GUILayout.Button("沿路径生成物体", GUILayout.Width(140)))
            {
                PrefabAssetType assetType = PrefabUtility.GetPrefabAssetType(template_Go);

                bool isPrefab = assetType != PrefabAssetType.NotAPrefab;

                if (isPrefab)
                {
                    CreateGoList(true);
                }
                else
                {
                    CreateGoList(false);
                }
            }

            EditorGUILayout.Space();

            if (GUILayout.Button("删除所有已生成物体", GUILayout.Width(140)))
            {
                DelectAllGos();
            }
        }

        void CreateLinePath()
        {
            EditorApplication.ExecuteMenuItem("GameObject/Create Empty");

            Selection.activeGameObject.name = "LinePath";

            Undo.AddComponent<HK_Path>(Selection.activeGameObject);
        }

        void ResetPathGoAxis()
        {
            if (Selection.count != 1 || Selection.activeGameObject.GetComponent<HK_Path>() == null)
            {
                Debug.LogError("HK_CreateGoByPath：只能选中一个物体，并拥有 HK_Path 组件");
                return;
            }

            HK_Path linePath = Selection.activeGameObject.GetComponent<HK_Path>();

            List<Transform> childList = new List<Transform>();

            // 将生成的子物体先移出来
            for (int i = 0; i < linePath.transform.childCount; i++)
            {
                childList.Add(linePath.transform.GetChild(i));
            }

            for (int i = 0; i < childList.Count; i++)
            {
                childList[i].SetParent(linePath.transform.parent);
            }

            int posCount = linePath.wayPoints.Count;

            Vector3 centerPos = Vector3.zero;

            for (int i = 0; i < posCount; i++)
            {
                centerPos += linePath.wayPoints[i];
            }

            centerPos = centerPos / posCount;

            linePath.transform.position = centerPos;

            // 将生成的子物体放回LineRenderer父物体下
            for (int i = 0; i < childList.Count; i++)
            {
                childList[i].SetParent(linePath.transform);
            }
        }

        void ResetWayPointsPos()
        {
            if (Selection.count != 1 || Selection.activeGameObject.GetComponent<HK_Path>() == null)
            {
                Debug.LogError("HK_CreateGoByPath：只能选中一个物体，并拥有 HK_Path 组件");
                return;
            }

            HK_Path linePath = Selection.activeGameObject.GetComponent<HK_Path>();

            for (int i = 0; i < linePath.wayPoints.Count; i++)
            {
                linePath.wayPoints[i] = linePath.transform.position + linePath.wayPointsOffset[i];
            }

            EditorUtility.SetDirty(linePath);
        }

        void CreateGoList(bool isPrefab)
        {
            if (Selection.count != 1 || Selection.activeGameObject.GetComponent<HK_Path>() == null)
            {
                Debug.LogError("HK_CreateGoByPath：只能选中一个物体，并拥有 HK_Path 组件");
                return;
            }

            if (template_Go == null)
            {
                Debug.LogError("HK_CreateGoByPath：没有选择需要生成的预设体");
                return;
            }

            HK_Path linePath = Selection.activeGameObject.GetComponent<HK_Path>();

            Vector3 offset = Vector3.up * offsetHeight;

            float totalLength = 0f;
            List<float> segmentLengths = new List<float>();

            // 计算路径的总长度及每段的长度
            for (int i = 0; i < linePath.wayPoints.Count - 1; i++)
            {
                float length = Vector3.Distance(linePath.wayPoints[i], linePath.wayPoints[i + 1]);
                segmentLengths.Add(length);
                totalLength += length;
            }

            // 重新计算生成物体的位置
            int remainCount = prefabCount - 2;

            if (isPrefab)
            {
                GameObject createGo = Instantiate(template_Go);
                Selection.activeGameObject = createGo;
            }
            else
            {
                Selection.activeGameObject = template_Go;
                EditorApplication.ExecuteMenuItem("Window/General/Hierarchy");
                EditorApplication.ExecuteMenuItem("Edit/Duplicate");
            }


            // 生成初始物体
            GameObject startGo = Selection.activeGameObject;
            startGo.transform.position = linePath.wayPoints[0] + offset;
            startGo.transform.rotation = Quaternion.LookRotation(linePath.wayPoints[1] - linePath.wayPoints[0], Vector3.up);
            startGo.transform.SetParent(linePath.transform);
            startGo.transform.Rotate(new Vector3(0, offsetYEuler, 0));

            if (isPrefab)
            {
                GameObject createGo = Instantiate(template_Go);
                Selection.activeGameObject = createGo;
            }
            else
            {
                Selection.activeGameObject = template_Go;
                EditorApplication.ExecuteMenuItem("Window/General/Hierarchy");
                EditorApplication.ExecuteMenuItem("Edit/Duplicate");
            }

            // 生成终点物体
            GameObject endGo = Selection.activeGameObject;
            endGo.transform.position = linePath.wayPoints[linePath.wayPoints.Count - 1] + offset;
            endGo.transform.rotation = Quaternion.LookRotation(linePath.wayPoints[linePath.wayPoints.Count - 2] - linePath.wayPoints[linePath.wayPoints.Count - 1], Vector3.up);
            endGo.transform.SetParent(linePath.transform);
            endGo.transform.Rotate(new Vector3(0, offsetYEuler, 0));

            for (int i = 0; i < remainCount; i++)
            {
                // 保证起始和终点模型在路径的两端
                float distanceAlongPath = (totalLength / (prefabCount - 1)) * (i + 1);

                Vector3 targetPos = Vector3.zero;

                int index = 0;

                for (int j = 0; j < segmentLengths.Count; j++)
                {
                    if (distanceAlongPath > segmentLengths[j])
                    {
                        distanceAlongPath -= segmentLengths[j];
                    }
                    else
                    {
                        targetPos = Vector3.Lerp(linePath.wayPoints[j], linePath.wayPoints[j + 1], distanceAlongPath / segmentLengths[j]);
                        index = j + 1;
                        break;
                    }
                }

                if (isPrefab)
                {
                    GameObject createGo = Instantiate(template_Go);
                    Selection.activeGameObject = createGo;
                }
                else
                {
                    Selection.activeGameObject = template_Go;
                    EditorApplication.ExecuteMenuItem("Window/General/Hierarchy");
                    EditorApplication.ExecuteMenuItem("Edit/Duplicate");
                }

                GameObject go = Selection.activeGameObject;
                go.transform.position = targetPos + offset;
                go.transform.rotation = Quaternion.LookRotation(linePath.wayPoints[index] - targetPos, Vector3.up);
                go.transform.SetParent(linePath.transform);
                go.transform.Rotate(new Vector3(0, offsetYEuler, 0));
            }

            Selection.activeGameObject = linePath.gameObject;
        }


        void DelectAllGos()
        {
            if (Selection.count != 1 || Selection.activeGameObject.GetComponent<HK_Path>() == null)
            {
                Debug.LogError("HK_CreateGoByPath：只能选中一个物体，并拥有 HK_Path 组件");
                return;
            }

            if (Selection.activeGameObject.transform.childCount <= 0)
                return;

            List<GameObject> goList = new List<GameObject>();

            for (int i = 0; i < Selection.activeGameObject.transform.childCount; i++)
            {
                goList.Add(Selection.activeGameObject.transform.GetChild(i).gameObject);
            }

            for (int i = 0; i < goList.Count; i++)
            {
                Undo.DestroyObjectImmediate(goList[i]);
            }
        }
    }
}